// java
package com.sunlake.spring.main.common.model.file.service.impl;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.sunlake.spring.main.common.model.file.dto.FileMergeDTO;
import com.sunlake.spring.main.common.model.file.mapper.FilesMapper;
import com.sunlake.spring.main.common.model.file.service.FileUploadService;
import com.sunlake.spring.main.common.response.R;
import com.sunlake.spring.main.common.utils.CurrentUserUtil;
import com.sunlake.spring.main.common.utils.JwtTokenUtil;
import com.sunlake.spring.main.common.utils.LoggerUtil;
import com.sunlake.spring.main.model.auth.mapper.UsersMapper;
import com.sunlake.spring.main.model.counselor.mapper.ResumesMapper;
import com.sunlake.spring.main.model.counselor.po.FilesPO;
import com.sunlake.spring.main.model.counselor.po.ResumesPO;
import com.sunlake.spring.main.model.counselor.service.impl.CounselorApplyServiceImpl;

import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;

@Service
public class ResumeUploadServiceImpl implements FileUploadService {
    private static final Logger log = LoggerUtil.getLogger(CounselorApplyServiceImpl.class);

    // 原配置值（可能是相对路径，如 ./uploads）
    @Value("${file.upload-dir}")
    private String UPLOAD_DIR;

    @Value("${file.access-prefix}")
    private String ACCESS_PREFIX;

    // 规范化后的绝对根路径
    private Path rootUploadDir;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private FilesMapper filesMapper;
    @Autowired
    private ResumesMapper resumesMapper;
    @Autowired
    private UsersMapper usersMapper;

    @PostConstruct
    public void initUploadDir() {
        Path configured = Paths.get(UPLOAD_DIR);
        if (!configured.isAbsolute()) {
            configured = Paths.get(System.getProperty("user.dir")).resolve(configured).normalize();
        } else {
            configured = configured.normalize();
        }
        this.rootUploadDir = configured;
        rootUploadDir = rootUploadDir.resolve("resumes");
        try {
            Files.createDirectories(rootUploadDir);
            Files.createDirectories(rootUploadDir.resolve("chunks"));
            log.info("上传根目录: {}", rootUploadDir);
        } catch (IOException e) {
            log.error("创建上传目录失败: {}", e.getMessage(), e);
        }
    }

    private static String safeSegment(String raw) {
        if (raw == null || raw.isEmpty()) return "default_md5";
        // 若出现重复或多值，取第一个
        String first = raw.split(",")[0];
        // 仅保留路径安全字符
        String cleaned = first.replaceAll("[^A-Za-z0-9._-]", "");
        return cleaned.isEmpty() ? "default_md5" : cleaned;
    }

    @Override
    public R<Map<String, Object>> uploadFile(MultipartFile file) throws IOException {
        Long userId = CurrentUserUtil.getCurrentUserId();
        if (userId == null) {
            return R.error(401, "未登录，无法上传文件");
        }

        String username = Optional.ofNullable(getCurrentUsername()).orElse("unknown");
        String originalFilename = file.getOriginalFilename();
        String extension = (originalFilename != null && originalFilename.lastIndexOf('.') >= 0)
                ? originalFilename.substring(originalFilename.lastIndexOf('.'))
                : ".pdf";
        String fileName = username + "_" + userId + "_" + System.currentTimeMillis() + extension;

        Path target = rootUploadDir.resolve(fileName);
        try {
            Files.createDirectories(target.getParent());
            file.transferTo(target.toFile());
        } catch (IOException e) {
            log.error("保存简历文件失败: {}", e.getMessage(), e);
            return R.error(500, "文件保存失败: " + e.getMessage());
        }

        Map<String, Object> result = new HashMap<>();
        result.put("fileName", fileName);
        result.put("filePath", ACCESS_PREFIX + "/" + fileName);
        result.put("fileSize", file.getSize());
        log.info("简历上传成功 userId={}, fileName={}, size={}", userId, fileName, file.getSize());
        return R.ok(200, "文件上传成功", result);
    }

    @Override
    public R<Map<String, Object>> uploadFileChunk(MultipartFile chunk, String md5, Integer index) throws IOException {
        if (chunk == null || chunk.isEmpty()) {
            return R.error(400, "分片文件不能为空");
        }
        String identifier = safeSegment(md5);
        int idx = index == null ? 0 : index;

        Long userId = CurrentUserUtil.getCurrentUserId();
        if (userId == null) {
            return R.error(401, "未登录，无法上传分片文件");
        }

        Path chunkDir = rootUploadDir.resolve("chunks").resolve(identifier);
        Files.createDirectories(chunkDir);

        Path chunkFile = chunkDir.resolve(idx + ".part");
        try {
            chunk.transferTo(chunkFile.toFile());
        } catch (IOException e) {
            log.error("保存分片失败 identifier={}, index={}, error={}", identifier, idx, e.getMessage(), e);
            return R.error(500, "分片文件保存失败: " + e.getMessage());
        }

        Map<String, Object> result = new HashMap<>();
        result.put("identifier", identifier);
        result.put("chunkIndex", idx);
        result.put("chunkSize", chunk.getSize());
        log.debug("分片上传成功 identifier={}, index={}, size={}", identifier, idx, chunk.getSize());
        return R.ok(200, "分片上传成功", result);
    }

    @Override
    public R<Map<String, Object>> mergeFile(FileMergeDTO mergeDTO) throws IOException {
        System.out.println("mergeDTO = " + mergeDTO);
        if (mergeDTO == null) {
            return R.error(400, "合并参数不能为空");
        }
        String identifier = safeSegment(
                Optional.ofNullable(mergeDTO.getFileId()).orElse(mergeDTO.getMd5())
        );
        Integer totalChunks = mergeDTO.getTotalChunks();
        if (totalChunks == null || totalChunks <= 0) {
            return R.error(400, "无效的分片数量");
        }

        Long userId = CurrentUserUtil.getCurrentUserId();
        if (userId == null) {
            return R.error(401, "未登录，无法合并文件");
        }
        String username = Optional.ofNullable(getCurrentUsername()).orElse("unknown");

        Path chunkDir = rootUploadDir.resolve("chunks").resolve(identifier);
        if (!Files.exists(chunkDir)) {
            return R.error(400, "分片文件目录不存在: " + chunkDir);
        }

        // 简单存在性校验
        for (int i = 0; i < totalChunks; i++) {
            if (!Files.exists(chunkDir.resolve(i + ".part"))) {
                return R.error(400, "第" + i + "个分片文件不存在");
            }
        }

        String originalFilename = mergeDTO.getFileName();
        String extension = (originalFilename != null && originalFilename.lastIndexOf('.') >= 0)
                ? originalFilename.substring(originalFilename.lastIndexOf('.') + 1)
                : "";
        String mergedFileName = username + "_" + userId + "_" + System.currentTimeMillis() + "." + extension.toLowerCase();
        Path mergedFilePath = rootUploadDir.resolve(mergedFileName);

        long mergedFileSize = 0L;
        try (FileOutputStream outputStream = new FileOutputStream(mergedFilePath.toFile())) {
            for (int i = 0; i < totalChunks; i++) {
                Path part = chunkDir.resolve(i + ".part");
                byte[] bytes = Files.readAllBytes(part);
                mergedFileSize += bytes.length;
                outputStream.write(bytes);
            }
            outputStream.flush();
        } catch (IOException e) {
            log.error("合并分片失败 identifier={}, error={}", identifier, e.getMessage(), e);
            return R.error(500, "文件合并失败: " + e.getMessage());
        }

        FilesPO filesPO = new FilesPO();
        filesPO.setFilename(mergedFileName);
        filesPO.setFileUrl(mergedFilePath.toString());
        filesPO.setFileSize(mergedFileSize);
        filesPO.setCreatedAt(LocalDateTime.now());
        filesPO.setUploaderId(Math.toIntExact(userId));
        filesMapper.insert(filesPO);

        Long inserdtedId = filesPO.getId();

//        FilesPO insertedFile = filesMapper.selectByPrimaryKey(inserdtedId);


        // 查询用户当前版本
        Integer currentVersion = resumesMapper.selectCurrentVersionByUserId(userId);
        int nextVersion = (currentVersion == null) ? 1 : currentVersion + 1;

        // 更新简历表，设置当前简历
        resumesMapper.updateIsCurrentByUserId(userId);



        ResumesPO resumesPO = new ResumesPO();
        resumesPO.setUserId(Math.toIntExact(userId));
        resumesPO.setFileId(inserdtedId);
        resumesPO.setVersion(nextVersion);
        resumesPO.setIsCurrent(1);
        resumesPO.setVisibility("private");
        resumesPO.setResumeUid(UUID.randomUUID().toString());
        resumesPO.setCreatedAt(LocalDateTime.now());
        resumesMapper.insert(resumesPO);

        // 可选：清理分片目录
        // Files.walk(chunkDir).sorted(Comparator.reverseOrder()).forEach(p -> p.toFile().delete());

        Map<String, Object> result = new HashMap<>();
        result.put("fileName", mergedFileName);
        result.put("filePath", ACCESS_PREFIX + "/" + mergedFileName);
        result.put("originalFilename", originalFilename);
        result.put("fileRecordId", inserdtedId);
        result.put("resumeId", resumesPO.getId());
        result.put("resumeUid", resumesPO.getResumeUid());
        result.put("fileSize", mergedFileSize);
        log.info("分片合并成功 userId={}, identifier={}, fileName={}, size={}", userId, identifier, mergedFileName, mergedFileSize);
        return R.ok(200, "文件合并成功", result);
    }

    private String getCurrentUsername() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String tokenHeader = request.getHeader("Authorization");
                if (tokenHeader != null && tokenHeader.startsWith("Bearer ")) {
                    String token = tokenHeader.substring(7).trim();
                    return jwtTokenUtil.getUsernameFromToken(token);
                }
            }
        } catch (Exception e) {
            log.warn("解析当前用户名失败: {}", e.getMessage());
        }
        return null;
    }


}
